# backtick_javascript: true
# use_strict: true

# This is based on an adaptation of Makoto Matsumoto and Takuji Nishimura's code
# done by Sean McCullough <banksean@gmail.com> and Dave Heitzman
# <daveheitzman@yahoo.com>, subsequently readapted from an updated version of
# ruby's random.c (rev c38a183032a7826df1adabd8aa0725c713d53e1c).
#
# The original copyright notice from random.c follows.
#
#   This is based on trimmed version of MT19937.  To get the original version,
#   contact <http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html>.
#
#   The original copyright notice follows.
#
#      A C-program for MT19937, with initialization improved 2002/2/10.
#      Coded by Takuji Nishimura and Makoto Matsumoto.
#      This is a faster version by taking Shawn Cokus's optimization,
#      Matthe Bellew's simplification, Isaku Wada's real version.
#
#      Before using, initialize the state by using init_genrand(mt, seed)
#      or init_by_array(mt, init_key, key_length).
#
#      Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
#      All rights reserved.
#
#      Redistribution and use in source and binary forms, with or without
#      modification, are permitted provided that the following conditions
#      are met:
#
#        1. Redistributions of source code must retain the above copyright
#           notice, this list of conditions and the following disclaimer.
#
#        2. Redistributions in binary form must reproduce the above copyright
#           notice, this list of conditions and the following disclaimer in the
#           documentation and/or other materials provided with the distribution.
#
#        3. The names of its contributors may not be used to endorse or promote
#           products derived from this software without specific prior written
#           permission.
#
#      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
#      "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
#      LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#      A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#      CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#      EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#      PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#      PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#      LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#      NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#      SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
#      Any feedback is very welcome.
#      http://www.math.keio.ac.jp/matumoto/emt.html
#      email: matumoto@math.keio.ac.jp

class ::Random
  mersenne_twister = %x{(function() {
    /* Period parameters */
    var N = 624;
    var M = 397;
    var MATRIX_A = 0x9908b0df;      /* constant vector a */
    var UMASK = 0x80000000;         /* most significant w-r bits */
    var LMASK = 0x7fffffff;         /* least significant r bits */
    var MIXBITS = function(u,v) { return ( ((u) & UMASK) | ((v) & LMASK) ); };
    var TWIST = function(u,v) { return (MIXBITS((u),(v)) >>> 1) ^ ((v & 0x1) ? MATRIX_A : 0x0); };

    function init(s) {
      var mt = {left: 0, next: N, state: new Array(N)};
      init_genrand(mt, s);
      return mt;
    }

    /* initializes mt[N] with a seed */
    function init_genrand(mt, s) {
      var j, i;
      mt.state[0] = s >>> 0;
      for (j=1; j<N; j++) {
        mt.state[j] = (1812433253 * ((mt.state[j-1] ^ (mt.state[j-1] >> 30) >>> 0)) + j);
        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
        /* In the previous versions, MSBs of the seed affect   */
        /* only MSBs of the array state[].                     */
        /* 2002/01/09 modified by Makoto Matsumoto             */
        mt.state[j] &= 0xffffffff;  /* for >32 bit machines */
      }
      mt.left = 1;
      mt.next = N;
    }

    /* generate N words at one time */
    function next_state(mt) {
      var p = 0, _p = mt.state;
      var j;

      mt.left = N;
      mt.next = 0;

      for (j=N-M+1; --j; p++)
        _p[p] = _p[p+(M)] ^ TWIST(_p[p+(0)], _p[p+(1)]);

      for (j=M; --j; p++)
        _p[p] = _p[p+(M-N)] ^ TWIST(_p[p+(0)], _p[p+(1)]);

      _p[p] = _p[p+(M-N)] ^ TWIST(_p[p+(0)], _p[0]);
    }

    /* generates a random number on [0,0xffffffff]-interval */
    function genrand_int32(mt) {
      /* mt must be initialized */
      var y;

      if (--mt.left <= 0) next_state(mt);
      y = mt.state[mt.next++];

      /* Tempering */
      y ^= (y >>> 11);
      y ^= (y << 7) & 0x9d2c5680;
      y ^= (y << 15) & 0xefc60000;
      y ^= (y >>> 18);

      return y >>> 0;
    }

    function int_pair_to_real_exclusive(a, b) {
      a >>>= 5;
      b >>>= 6;
      return(a*67108864.0+b)*(1.0/9007199254740992.0);
    }

    // generates a random number on [0,1) with 53-bit resolution
    function genrand_real(mt) {
      /* mt must be initialized */
      var a = genrand_int32(mt), b = genrand_int32(mt);
      return int_pair_to_real_exclusive(a, b);
    }

    return { genrand_real: genrand_real, init: init };
  })()}

  `var MAX_INT = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1`

  self::MERSENNE_TWISTER_GENERATOR = `{
    new_seed: function() { return Math.round(Math.random() * MAX_INT); },
    reseed: function(seed) { return mersenne_twister.init(seed); },
    rand: function(mt) { return mersenne_twister.genrand_real(mt); }
  }`

  self.generator = self::MERSENNE_TWISTER_GENERATOR
end
